import { Request, Response, NextFunction } from 'express';
import { prisma } from '../../config/database';
import { BaseController } from '../../utils/autoBind';
import { ResponseUtils } from '../../utils/responseUtils';
import { BUSINESS_ERROR_CODES, VALIDATION_ERROR_CODES, COMMON_ERROR_CODES } from '../../utils/errorCodes';
import { v4 as uuidv4 } from 'uuid';
import axios from 'axios';
import FormData from 'form-data';
import fs from 'fs';
/**
 * 流式模式（智能助手）
 *   data: {"event": "agent_thought",
 * "id": "8dcf3648-fbad-407a-85dd-73a6f43aeb9f",
 * "task_id": "9cf1ddd7-f94b-459b-b942-b77b26c59e9b",
 * "message_id": "1fb10045-55fd-4040-99e6-d048d07cbad3",
 * "position": 1, "thought": "",
 * "observation": "", "tool": "", "tool_input": "", "created_at": 1705639511, "message_files": [], "conversation_id": "c216c595-2d89-438c-b33c-aae5ddddd142"}
  data: {"event": "agent_thought", "id": "8dcf3648-fbad-407a-85dd-73a6f43aeb9f", "task_id": "9cf1ddd7-f94b-459b-b942-b77b26c59e9b", "message_id": "1fb10045-55fd-4040-99e6-d048d07cbad3", "position": 1, "thought": "", "observation": "", "tool": "dalle3", "tool_input": "{\"dalle3\": {\"prompt\": \"cute Japanese anime girl with white hair, blue eyes, bunny girl suit\"}}", "created_at": 1705639511, "message_files": [], "conversation_id": "c216c595-2d89-438c-b33c-aae5ddddd142"}
  data: {"event": "message_file", "id": "d75b7a5c-ce5e-442e-ab1b-d6a5e5b557b0", "type": "image", "belongs_to": "assistant", "url": "http://127.0.0.1:5001/files/tools/d75b7a5c-ce5e-442e-ab1b-d6a5e5b557b0.png?timestamp=1705639526&nonce=70423256c60da73a9c96d1385ff78487&sign=7B5fKV9890YJuqchQvrABvW4AIupDvDvxGdu1EOJT94=", "conversation_id": "c216c595-2d89-438c-b33c-aae5ddddd142"}
  data: {"event": "agent_thought", "id": "8dcf3648-fbad-407a-85dd-73a6f43aeb9f", "task_id": "9cf1ddd7-f94b-459b-b942-b77b26c59e9b", "message_id": "1fb10045-55fd-4040-99e6-d048d07cbad3", "position": 1, "thought": "", "observation": "image has been created and sent to user already, you should tell user to check it now.", "tool": "dalle3", "tool_input": "{\"dalle3\": {\"prompt\": \"cute Japanese anime girl with white hair, blue eyes, bunny girl suit\"}}", "created_at": 1705639511, "message_files": ["d75b7a5c-ce5e-442e-ab1b-d6a5e5b557b0"], "conversation_id": "c216c595-2d89-438c-b33c-aae5ddddd142"}
  data: {"event": "agent_thought", "id": "67a99dc1-4f82-42d3-b354-18d4594840c8", "task_id": "9cf1ddd7-f94b-459b-b942-b77b26c59e9b", "message_id": "1fb10045-55fd-4040-99e6-d048d07cbad3", "position": 2, "thought": "", "observation": "", "tool": "", "tool_input": "", "created_at": 1705639511, "message_files": [], "conversation_id": "c216c595-2d89-438c-b33c-aae5ddddd142"}
  data: {"event": "agent_message", "id": "1fb10045-55fd-4040-99e6-d048d07cbad3", "task_id": "9cf1ddd7-f94b-459b-b942-b77b26c59e9b", "message_id": "1fb10045-55fd-4040-99e6-d048d07cbad3", "answer": "I have created an image of a cute Japanese", "created_at": 1705639511, "conversation_id": "c216c595-2d89-438c-b33c-aae5ddddd142"}
  data: {"event": "agent_message", "id": "1fb10045-55fd-4040-99e6-d048d07cbad3", "task_id": "9cf1ddd7-f94b-459b-b942-b77b26c59e9b", "message_id": "1fb10045-55fd-4040-99e6-d048d07cbad3", "answer": " anime girl with white hair and blue", "created_at": 1705639511, "conversation_id": "c216c595-2d89-438c-b33c-aae5ddddd142"}
  data: {"event": "agent_message", "id": "1fb10045-55fd-4040-99e6-d048d07cbad3", "task_id": "9cf1ddd7-f94b-459b-b942-b77b26c59e9b", "message_id": "1fb10045-55fd-4040-99e6-d048d07cbad3", "answer": " eyes wearing a bunny girl" ,"created_at": 1705639511, "conversation_id": "c216c595-2d89-438c-b33c-aae5ddddd142"}
  data: {"event": "agent_message", "id": "1fb10045-55fd-4040-99e6-d048d07cbad3", "task_id": "9cf1ddd7-f94b-459b-b942-b77b26c59e9b", "message_id": "1fb10045-55fd-4040-99e6-d048d07cbad3", "answer": " suit .", "created_at": 1705639511, "conversation_id": "c216c595-2d89-438c-b33c-aae5ddddd142"}
  data: {"event": "agent_thought", "id": "67a99dc1-4f82-42d3-b354-18d4594840c8", "task_id": "9cf1ddd7-f94b-459b-b942-b77b26c59e9b", "message_id": "1fb10045-55fd-4040-99e6-d048d07cbad3", "position": 2, "thought": "I have created an image of a cute Japanese anime girl with white hair and blue eyes wearing a bunny girl suit.", "observation": "", "tool": "", "tool_input": "", "created_at": 1705639511, "message_files": [], "conversation_id": "c216c595-2d89-438c-b33c-aae5ddddd142"}
  data: {"event": "message_end", "id": "5e52ce04-874b-4d27-9045-b3bc80def685", "conversation_id": "45701982-8118-4bc5-8e9b-64562b4555f2", "metadata": {"usage": {"prompt_tokens": 1033, "prompt_unit_price": "0.001", "prompt_price_unit": "0.001", "prompt_price": "0.0010330", "completion_tokens": 135, "completion_unit_price": "0.002", "completion_price_unit": "0.001", "completion_price": "0.0002700", "total_tokens": 1168, "total_price": "0.0013030", "currency": "USD", "latency": 1.381760165997548}, "retriever_resources": [{"position": 1, "dataset_id": "101b4c97-fc2e-463c-90b1-5261a4cdcafb", "dataset_name": "iPhone", "document_id": "8dd1ad74-0b5f-4175-b735-7d98bbbb4e00", "document_name": "iPhone List", "segment_id": "ed599c7f-2766-4294-9d1d-e5235a61270a", "score": 0.98457545, "content": "\"Model\",\"Release Date\",\"Display Size\",\"Resolution\",\"Processor\",\"RAM\",\"Storage\",\"Camera\",\"Battery\",\"Operating System\"\n\"iPhone 13 Pro Max\",\"September 24, 2021\",\"6.7 inch\",\"1284 x 2778\",\"Hexa-core (2x3.23 GHz Avalanche + 4x1.82 GHz Blizzard)\",\"6 GB\",\"128, 256, 512 GB, 1TB\",\"12 MP\",\"4352 mAh\",\"iOS 15\""}]}}
  data: {"event": "tts_message", "conversation_id": "23dd85f3-1a41-4ea0-b7a9-062734ccfaf9", "message_id": "a8bdc41c-13b2-4c18-bfd9-054b9803038c", "created_at": 1721205487, "task_id": "3bf8a0bb-e73b-4690-9e66-4e429bad8ee7", "audio": "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"}
  data: {"event": "tts_message_end", "conversation_id": "23dd85f3-1a41-4ea0-b7a9-062734ccfaf9", "message_id": "a8bdc41c-13b2-4c18-bfd9-054b9803038c", "created_at": 1721205487, "task_id": "3bf8a0bb-e73b-4690-9e66-4e429bad8ee7", "audio": ""}

 */
export interface DifyMessage {
  /** agent_message|agent_thought|message_file|message_end|tts_message|tts_message_end */
  event: string;
  id: string;
  task_id: string;
  message_id: string;
  position: number;
  thought: string;
  observation: string;
  tool: string;
  tool_input: string;
  created_at: number;
  message_files: string[];
  conversation_id: string;
}

// Dify API 配置
const DIFY_CONFIG = {
  baseUrl: 'http://dify.vip.hnhxzkj.com/v1',
  apiKey: 'app-wnqT3MprLsLJZNeWYf3ixdHb',
};

const DIFY_WORKFLOW_CONFIG = {
  baseUrl: 'http://dify.vip.hnhxzkj.com/v1', // 修正基础 URL
  apiKey: 'app-7TcYOQHuhxgOFTX915tQNjOk'
};

// 阿里云语音识别配置
const ALIYUN_CONFIG = {
  accessKeyId: process.env.ALIYUN_ACCESS_KEY_ID || '',
  accessKeySecret: process.env.ALIYUN_ACCESS_KEY_SECRET || '',
  endpoint: process.env.ALIYUN_DASHSCOPE_ENDPOINT || 'https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation',
  apiKey: process.env.ALIYUN_DASHSCOPE_API_KEY || 'sk-e6cc94eddc7348359673d4c6a9b87e91',
  region: process.env.ALIYUN_REGION || 'cn-shanghai'
};

export class DifyAIController extends BaseController {
  /**
   * workflow 聊天 - blocking 模式
   * 等待整个 workflow 执行完成后一次性返回结果
   */
  async workflowChat(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { message, conversation_id, inputs = {}} = req.body;
      const userId = req.user!.id;

      if (!message) {
        ResponseUtils.sendError(res, VALIDATION_ERROR_CODES.REQUIRED_FIELD_MISSING, '消息内容不能为空');
        return;
      }

      // 确保 inputs 是对象格式
      const processedInputs = typeof inputs === 'string' ? JSON.parse(inputs) : inputs;
      
      // 构建 workflow 请求数据
      const workflowRequestData: any = {
        inputs: {
          ...processedInputs,
          // 根据 Dify workflow 的变量定义来设置
          // 这里假设 workflow 定义了 "user_input" 变量来接收用户消息
          user_input: message
        },
        response_mode: 'blocking', // 强制使用 blocking 模式
        user: userId.toString()
      };

      // 如果有会话ID，添加到请求中
      if (conversation_id) {
        workflowRequestData.conversation_id = conversation_id;
      }

      // 如果有文件上传，添加到 inputs 中
      if (req.files && Array.isArray(req.files) && req.files.length > 0) {
        const files = req.files.map((file: any) => ({
          type: 'image', // 目前 Dify 主要支持图片
          transfer_method: 'local_file',
          upload_file_id: file.filename // 使用文件名作为文件ID
        }));
        if (files && files.length > 0) {
          // 根据 workflow 变量名来设置，例如 "uploaded_files"
          workflowRequestData.inputs.uploaded_files = files;
        }
      }

      console.log('发送 workflow 请求:', JSON.stringify(workflowRequestData, null, 2));

      try {
        // 调用 Dify Workflow API
        const response = await axios.post(
          `${DIFY_WORKFLOW_CONFIG.baseUrl}/workflows/run`, // 修正端点路径
          workflowRequestData,
          {
            headers: {
              'Authorization': `Bearer ${DIFY_WORKFLOW_CONFIG.apiKey}`,
              'Content-Type': 'application/json'
            },
            timeout: 120000 // 2分钟超时，workflow 可能需要更长时间
          }
        );

        console.log('Workflow 响应状态:', response.status);
        console.log('Workflow 响应数据:', response.data);

        // 处理 workflow 响应
        const workflowResponse = response.data;
        
        // 保存对话记录
        try {
          let conversation = await prisma.assistantConversation.findFirst({
            where: { userId: userId }
          });

          if (!conversation) {
            conversation = await prisma.assistantConversation.create({
              data: {
                userId: userId,
                sessionId: uuidv4()
              }
            });
          }

          // 保存用户消息
          await prisma.assistantMessage.create({
            data: {
              conversationId: conversation.id,
              messageType: 'USER',
              content: message,
              messageFormat: 'TEXT'
            }
          });

          // 保存AI回复
          if (workflowResponse.answer) {
            await prisma.assistantMessage.create({
              data: {
                conversationId: conversation.id,
                messageType: 'ASSISTANT',
                content: workflowResponse.answer,
                messageFormat: 'TEXT'
              }
            });
          }
        } catch (dbError) {
          console.error('保存对话记录失败:', dbError);
          // 不影响主要功能，继续执行
        }

        // 返回完整的 workflow 结果
        ResponseUtils.success(res, {
          workflow_run_id: workflowResponse.workflow_run_id,
          task_id: workflowResponse.task_id,
          data: {
            id: workflowResponse.data?.id,
            workflow_id: workflowResponse.data?.workflow_id,
            status: workflowResponse.data?.status,
            outputs: workflowResponse.data?.outputs,
            error: workflowResponse.data?.error,
            elapsed_time: workflowResponse.data?.elapsed_time,
            total_tokens: workflowResponse.data?.total_tokens,
            total_steps: workflowResponse.data?.total_steps,
            created_at: workflowResponse.data?.created_at,
            finished_at: workflowResponse.data?.finished_at
          }
        }, 'Workflow 执行完成');

      } catch (error: any) {
        console.error('Dify Workflow API 调用失败:', error);

        // 添加详细的错误信息
        let errorMessage = 'Workflow 执行失败，请稍后再试。';
        let errorCode = COMMON_ERROR_CODES.SERVICE_UNAVAILABLE;

        if (error.response?.status === 400) {
          errorMessage = 'Workflow 参数错误，请检查输入格式。';
          errorCode = VALIDATION_ERROR_CODES.FIELD_FORMAT_ERROR;
          console.error('响应数据:', error.response?.data);
        } else if (error.response?.status === 401) {
          errorMessage = 'Workflow 服务认证失败，请检查配置。';
          errorCode = COMMON_ERROR_CODES.UNAUTHORIZED;
        } else if (error.response?.status === 429) {
          errorMessage = 'Workflow 服务繁忙，请稍后再试。';
          errorCode = COMMON_ERROR_CODES.TOO_MANY_REQUESTS;
        } else if (error.response?.status === 500) {
          errorMessage = 'Workflow 服务内部错误，请稍后再试。';
          errorCode = COMMON_ERROR_CODES.INTERNAL_SERVER_ERROR;
        } else if (error.code === 'ECONNABORTED') {
          errorMessage = 'Workflow 执行超时，请稍后再试。';
          errorCode = COMMON_ERROR_CODES.GATEWAY_TIMEOUT;
        }

        ResponseUtils.sendError(res, errorCode, errorMessage);
      }
    } catch (error) {
      next(error);
    }
  }

  /**
   * 获取下一轮建议问题列表
   * 使用 Dify API 的 /messages/{message_id}/suggested 接口
   */
  async getSuggestedQuestions(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { message_id } = req.params;
      const userId = req.user!.id;

      if (!message_id) {
        ResponseUtils.sendError(res, VALIDATION_ERROR_CODES.REQUIRED_FIELD_MISSING, '消息ID不能为空');
        return;
      }

      try {
        // 调用 Dify 获取建议问题 API
        const response = await axios.get(
          `${DIFY_CONFIG.baseUrl}/messages/${message_id}/suggested`,
          {
            headers: {
              'Authorization': `Bearer ${DIFY_CONFIG.apiKey}`,
              'Content-Type': 'application/json'
            },
            params: {
              user: userId.toString()
            }
          }
        );

        console.log('获取建议问题响应状态:', response.status);
        console.log('建议问题数据:', response.data);

        // 处理响应数据
        const suggestedData = response.data;
        
        // 返回建议问题列表
        ResponseUtils.success(res, {
          suggested_questions: suggestedData.data || [],
          message_id: message_id
        }, '获取建议问题成功');

      } catch (error: any) {
        console.error('Dify 获取建议问题 API 调用失败:', error);

        // 添加详细的错误信息
        let errorMessage = '获取建议问题失败，请稍后再试。';
        let errorCode = COMMON_ERROR_CODES.SERVICE_UNAVAILABLE;

        if (error.response?.status === 400) {
          errorMessage = '请求参数错误，请检查消息ID格式。';
          errorCode = VALIDATION_ERROR_CODES.FIELD_FORMAT_ERROR;
          console.error('响应数据:', error.response?.data);
        } else if (error.response?.status === 401) {
          errorMessage = 'AI 服务认证失败，请检查配置。';
          errorCode = COMMON_ERROR_CODES.UNAUTHORIZED;
        } else if (error.response?.status === 404) {
          errorMessage = '消息不存在或已过期。';
          errorCode = BUSINESS_ERROR_CODES.RESOURCE_NOT_FOUND;
        } else if (error.response?.status === 429) {
          errorMessage = 'AI 服务繁忙，请稍后再试。';
          errorCode = COMMON_ERROR_CODES.TOO_MANY_REQUESTS;
        } else if (error.response?.status === 500) {
          errorMessage = 'AI 服务内部错误，请稍后再试。';
          errorCode = COMMON_ERROR_CODES.INTERNAL_SERVER_ERROR;
        }

        ResponseUtils.sendError(res, errorCode, errorMessage);
      }
    } catch (error) {
      next(error);
    }
  }

  /**
   * Dify AI 聊天 - 流式响应
   * 支持文本对话和文件上传
   */
  async chat(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      let { message, conversation_id, inputs = {}, response_mode = 'streaming' } = req.body;
      const userId = req.user!.id;

      if (!message) {
        ResponseUtils.sendError(res, VALIDATION_ERROR_CODES.REQUIRED_FIELD_MISSING, '消息内容不能为空');
        return;
      }
      inputs = typeof inputs === 'string' ? JSON.parse(inputs) : inputs;
      inputs.query = message;

      // 设置响应头，支持流式传输
      res.setHeader('Content-Type', 'text/event-stream');
      res.setHeader('Cache-Control', 'no-cache');
      res.setHeader('Connection', 'keep-alive');
      res.setHeader('Access-Control-Allow-Origin', '*');
      res.setHeader('Access-Control-Allow-Headers', 'Cache-Control');

      try {
        // 构建 Dify API 请求数据
        const requestData: any = {
          query: message,
          user: userId.toString(),
          inputs: typeof inputs === 'string' ? JSON.parse(inputs) : inputs,
          response_mode: response_mode || 'streaming',
          auto_generate_name: true
        };

        // 如果有会话ID，添加到请求中
        if (conversation_id) {
          requestData.conversation_id = conversation_id;
        }

        // 如果有文件上传，添加到请求中
        if (req.files && Array.isArray(req.files) && req.files.length > 0) {
          const files = req.files.map((file: any) => ({
            type: 'image', // 目前 Dify 主要支持图片
            transfer_method: 'local_file',
            upload_file_id: file.filename // 使用文件名作为文件ID
          }));
          if (files && files.length > 0) {
            requestData.files = files;
          }
        }

        // 发送开始标记
        console.log('发送开始标记');
        res.write('data: {"type": "start", "message": "开始生成回复..."}\n\n');
        res.flushHeaders(); // 确保头部立即发送

        // 调用 Dify API
        const response = await axios.post(
          `${DIFY_CONFIG.baseUrl}/chat-messages`,
          requestData,
          {
            headers: {
              'Authorization': `Bearer ${DIFY_CONFIG.apiKey}`,
              'Content-Type': 'application/json'
            },
            responseType: 'stream',
            timeout: 30000 // 30秒超时
          }
        );

        const stream = response.data;
        let fullResponse = '';
        let fullResponseWithThought = '';
        let isThinkingEnd: boolean = false;
        let isThinking: boolean = false;
        let finalConversationId = conversation_id || 'new_session'; // 初始化会话ID
        let messageId = '';
        
        // 添加数据缓冲机制
        let buffer = '';
        
        // 处理流式响应
        stream.on('data', (chunk: Buffer) => {
          const chunkStr = chunk.toString();
          console.log('收到 Dify 原始数据:', chunkStr);

          // 将新数据添加到缓冲区
          buffer += chunkStr;
          
          // 尝试从缓冲区中提取完整的行
          let newlineIndex;
          while ((newlineIndex = buffer.indexOf('\n')) !== -1) {
            // 提取一行数据
            const line = buffer.substring(0, newlineIndex);
            buffer = buffer.substring(newlineIndex + 1);
            
            // 处理这一行数据
            let isDataLine = line.startsWith('data: ');
            if (isDataLine) {
              const data = line.slice(6);
              try {
                const parsed = JSON.parse(data);
                console.log('Dify 事件类型:', parsed.event, '完整数据:', parsed);
                
                // 添加事件类型统计
                if (!(global as any).eventCounts) {
                  (global as any).eventCounts = {};
                }
                (global as any).eventCounts[parsed.event] = ((global as any).eventCounts[parsed.event] || 0) + 1;
                console.log('事件统计:', (global as any).eventCounts);
                
                if (parsed.event == "agent_message") {
                  let answer = parsed.answer;
                  if (!answer) {
                    console.log('agent_message 事件但 answer 为空，跳过');
                    continue;
                  }
                  if (!isThinkingEnd) {
                    if (!isThinking) {
                      isThinking = answer.includes("<think>");
                      if (isThinking) {
                        console.log('检测到思考模式，跳过');
                        continue;
                      }
                    } else {
                      console.log("dify is thinking");
                      let endThinkTag = "</think>";
                      let endThinkPos = answer.indexOf(endThinkTag);
                      if (endThinkPos == -1) {
                        //还在思考中，返回的全是思考的内容
                        console.log('还在思考中，跳过');
                        continue;
                      } else {
                        isThinking = false;
                        isThinkingEnd = true;
                        console.log('思考结束，开始处理内容');
                      }
                      //截取</think>标签后边的内容
                      let content = answer.slice(endThinkPos + endThinkTag.length);
                      content = content.trim();
                      if (content == "") {
                        console.log('思考标签后内容为空，跳过');
                        continue;
                      }
                      fullResponse += content;
                      console.log("chunk", content);

                      // 转义 JSON 字符串中的特殊字符
                      const escapedContent = content
                        .replace(/\\/g, '\\\\')
                        .replace(/"/g, '\\"')
                        .replace(/\n/g, '\\n')
                        .replace(/\r/g, '\\r')
                        .replace(/\t/g, '\\t');

                      res.write(`data: {"type": "chunk", "message_id": "${messageId}", "message": "${escapedContent}"}\n\n`);
                      res.flush(); // 立即刷新缓冲区
                      continue;
                    }
                  }

                  let content = answer;
                  fullResponse += content;
                  console.log("chunk", content);

                  // 转义 JSON 字符串中的特殊字符
                  const escapedContent = content
                    .replace(/\\/g, '\\\\')
                    .replace(/"/g, '\\"')
                    .replace(/\n/g, '\\n')
                    .replace(/\r/g, '\\r')
                    .replace(/\t/g, '\\t');
                  
                  // 更新会话ID
                  if (parsed.conversation_id) {
                    finalConversationId = parsed.conversation_id;
                    console.log('更新会话ID:', finalConversationId);
                  }
                  if (parsed.message_id) {
                    messageId = parsed.message_id;
                  }
                  res.write(`data: {"type": "chunk", "message_id": "${messageId}", "message": "${escapedContent}"}\n\n`);
                  res.flush(); // 立即刷新缓冲区
                } else if (parsed.event == 'agent_thought') {
                  let thought = parsed.thought;
                  if (thought?.trim() == "") {
                    console.log('agent_thought 事件但 thought 为空，跳过');
                    continue;
                  }
                  fullResponseWithThought = thought;
                  console.log("agent_thought end", fullResponseWithThought);
                } else if (parsed.event == 'message_end') {
                  console.log("✅ 收到 message_end 事件");
                  console.log("message_end", fullResponse);
                  console.log("当前会话ID:", finalConversationId);
                  console.log("Dify 返回的会话ID:", parsed.conversation_id);
                  
                  // 流结束
                  // 转义 JSON 字符串中的特殊字符
                  const escapedFullResponse = fullResponse
                    .replace(/\\/g, '\\\\')
                    .replace(/"/g, '\\"')
                    .replace(/\n/g, '\\n')
                    .replace(/\r/g, '\\r')
                    .replace(/\t/g, '\\t');
                  
                  // 更新会话ID
                  if (parsed.conversation_id) {
                    finalConversationId = parsed.conversation_id;
                    console.log('✅ 最终会话ID 已更新:', finalConversationId);
                  }
                  if (parsed.message_id) {
                    messageId = parsed.message_id;
                  }
                  
                  res.write(`data: {"type": "end", "conversation_id": "${finalConversationId}", "message_id": "${messageId}", "message": "${escapedFullResponse}"}\n\n`);
                  res.flush(); // 立即刷新缓冲区
                  res.end();
                  console.log('✅ message_end 事件处理完成，响应已结束');
                  return;
                } else {
                  console.log('⚠️ 未处理的事件类型:', parsed.event);
                }
              } catch (e: any) {
                console.error('解析行失败:', e.message, '原始数据:', line);
                console.log('⚠️ 这可能是数据分割导致的，等待更多数据...');
              }
            } else {
              console.log('非数据行，跳过:', line);
            }
          }
        });

        stream.on('end', async () => {
          console.log("Dify 流结束事件触发");
          console.log("最终完整回复:", fullResponse);
          console.log("最终会话ID:", finalConversationId);
          console.log("响应是否已结束:", res.writableEnded);
          console.log("事件统计:", (global as any).eventCounts);
          console.log("剩余缓冲区数据:", buffer);

          // 处理剩余的缓冲区数据
          if (buffer.trim()) {
            console.log("处理剩余缓冲区数据...");
            const lines = buffer.split('\n');
            for (const line of lines) {
              if (line.trim() && line.startsWith('data: ')) {
                try {
                  const data = line.slice(6);
                  const parsed = JSON.parse(data);
                  console.log('处理剩余数据中的事件:', parsed.event);
                  
                  if (parsed.event === 'message_end') {
                    console.log("✅ 在剩余数据中找到 message_end 事件");
                    console.log("message_end", fullResponse);
                    console.log("Dify 返回的会话ID:", parsed.conversation_id);
                    
                    // 更新会话ID
                    if (parsed.conversation_id) {
                      finalConversationId = parsed.conversation_id;
                      console.log('✅ 最终会话ID 已更新:', finalConversationId);
                    }
                    if (parsed.message_id) {
                      messageId = parsed.message_id;
                    }
                    
                    // 发送结束事件
                    const escapedFullResponse = fullResponse
                      .replace(/\\/g, '\\\\')
                      .replace(/"/g, '\\"')
                      .replace(/\n/g, '\\n')
                      .replace(/\r/g, '\\r')
                      .replace(/\t/g, '\\t');
                    
                    res.write(`data: {"type": "end", "conversation_id": "${finalConversationId}", "message_id": "${messageId}", "message": "${escapedFullResponse}"}\n\n`);
                    res.flush();
                    res.end();
                    console.log('✅ 剩余数据中的 message_end 事件处理完成');
                    return;
                  }
                } catch (e: any) {
                  console.error('处理剩余数据失败:', e.message, '原始数据:', line);
                }
              }
            }
          }

          // 如果 Dify 没有发送 message_end 事件，手动发送 end 事件
          if (fullResponse && !res.writableEnded) {
            console.log("手动发送结束事件");
            const escapedFullResponse = fullResponse
              .replace(/\\/g, '\\\\')
              .replace(/"/g, '\\"')
              .replace(/\n/g, '\\n')
              .replace(/\r/g, '\\r')
              .replace(/\t/g, '\\t');
            
            let data = `data: {"type": "end", "conversation_id": "${finalConversationId}", "message_id": "${messageId}", "message": "${escapedFullResponse}"}\n\n`;
            console.log("data", data);
            res.write(data);
            res.flush();
            res.end();
            console.log("✅ 手动结束事件发送完成");
          } else {
            console.log("不需要手动发送结束事件");
          }

          // 保存完整的对话记录
          try {
            let conversation = await prisma.assistantConversation.findFirst({
              where: { userId: userId }
            });

            if (!conversation) {
              conversation = await prisma.assistantConversation.create({
                data: {
                  userId: userId,
                  sessionId: uuidv4()
                }
              });
            }

            // 保存用户消息
            await prisma.assistantMessage.create({
              data: {
                conversationId: conversation.id,
                messageType: 'USER',
                content: message,
                messageFormat: 'TEXT'
              }
            });

            // 保存AI回复
            await prisma.assistantMessage.create({
              data: {
                conversationId: conversation.id,
                messageType: 'ASSISTANT',
                content: fullResponse,
                messageFormat: 'TEXT'
              }
            });
          } catch (dbError) {
            console.error('保存对话记录失败:', dbError);
          }
        });

        stream.on('error', (error: any) => {
          console.error('流式响应错误:', error);
          res.write('data: {"type": "error", "message": "抱歉，AI服务出现错误，请稍后再试。"}\n\n');
          res.flush(); // 立即刷新缓冲区
          res.end();
        });

      } catch (error: any) {
        console.error('Dify API 调用失败:', error);

        // 添加详细的错误信息
        let errorMessage = 'AI 服务暂时不可用，请稍后再试。';

        if (error.response?.status === 400) {
          errorMessage = '请求参数错误，请检查输入格式。';
          console.error('响应数据:', error.response?.data);
        } else if (error.response?.status === 401) {
          errorMessage = 'AI 服务认证失败，请检查配置。';
        } else if (error.response?.status === 429) {
          errorMessage = 'AI 服务繁忙，请稍后再试。';
        } else if (error.response?.status === 500) {
          errorMessage = 'AI 服务内部错误，请稍后再试。';
        }

        res.write(`data: {"type": "error", "message": "${errorMessage}"}\n\n`);
        res.flush(); // 立即刷新缓冲区
        res.end();
      }
    } catch (error) {
      next(error);
    }
  }

  /**
   * 语音转文字
   * 使用 Dify API 的 /audio-to-text 接口
   */
  async voiceToText(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const userId = req.user?.id;
      if (!userId) {
        ResponseUtils.sendError(res, BUSINESS_ERROR_CODES.USER_NOT_FOUND, '用户不存在');
        return;
      }

      if (!req.file) {
        ResponseUtils.sendError(res, VALIDATION_ERROR_CODES.REQUIRED_FIELD_MISSING, '请上传音频文件');
        return;
      }

      // 检查文件格式
      const allowedMimeTypes = [
        'audio/mpeg',           // MP3
        'audio/mp3',            // MP3 (某些系统)
        'audio/wav',            // WAV
        'audio/x-wav',          // WAV (某些系统)
        'audio/mp4',            // M4A
        'audio/x-m4a',          // M4A (某些系统)
        'audio/aac',            // AAC
        'audio/x-aac'           // AAC (某些系统)
      ];

      if (!allowedMimeTypes.includes(req.file.mimetype)) {
        // 删除临时文件
        try {
          fs.unlinkSync(req.file.path);
        } catch (unlinkError) {
          console.error('删除临时文件失败:', unlinkError);
        }

        ResponseUtils.sendError(res, VALIDATION_ERROR_CODES.FIELD_FORMAT_ERROR, '音频文件格式不支持');
        return;
      }

      try {
        // 构建 FormData 用于 Dify API 调用
        const formData = new FormData();
        formData.append('file', fs.createReadStream(req.file.path));
        formData.append('user', userId.toString());

        console.log('发送语音转文字请求到 Dify API:', {
          fileName: req.file.originalname,
          fileSize: req.file.size,
          mimeType: req.file.mimetype,
          userId: userId
        });

        // 调用 Dify 语音转文字 API
        const response = await axios.post(
          `${DIFY_CONFIG.baseUrl}/audio-to-text`,
          formData,
          {
            headers: {
              'Authorization': `Bearer ${DIFY_CONFIG.apiKey}`,
              ...formData.getHeaders()
            },
            timeout: 30000 // 30秒超时
          }
        );

        const { text } = response.data;

        // 删除临时文件
        try {
          fs.unlinkSync(req.file.path);
        } catch (unlinkError) {
          console.error('删除临时文件失败:', unlinkError);
        }

        ResponseUtils.success(res, {
          text: text,
          fileInfo: {
            originalName: req.file.originalname,
            size: req.file.size,
            mimeType: req.file.mimetype
          }
        }, '语音转文字成功');

      } catch (error: any) {
        console.error('Dify 语音转文字 API 调用失败:', error);

        // 删除临时文件
        try {
          fs.unlinkSync(req.file.path);
        } catch (unlinkError) {
          console.error('删除临时文件失败:', unlinkError);
        }

        // 根据不同的错误状态码返回相应的错误信息
        if (error.response?.status === 401) {
          ResponseUtils.sendError(res, COMMON_ERROR_CODES.UNAUTHORIZED, 'AI 服务认证失败，请检查配置');
        } else if (error.response?.status === 400) {
          ResponseUtils.sendError(res, VALIDATION_ERROR_CODES.FIELD_FORMAT_ERROR, '音频文件格式不支持或文件过大');
        } else if (error.response?.status === 413) {
          ResponseUtils.sendError(res, VALIDATION_ERROR_CODES.FIELD_FORMAT_ERROR, '音频文件过大，请上传小于10MB的文件');
        } else if (error.response?.status === 415) {
          // 415 错误：不支持的媒体类型
          // const errorDetails = {
          //   supportedFormats: ['MP3', 'WAV', 'M4A', 'AAC'],
          //   recommendedFormat: 'MP3',
          //   conversionTools: ['FFmpeg', '在线转换工具', '音频编辑软件'],
          //   currentFormat: req.file.mimetype,
          //   fileExtension: req.file.originalname?.split('.').pop() || 'unknown',
          //   difyError: error.response?.data?.message || 'Audio type not allowed'
          // };

          ResponseUtils.sendError(
            res, 
            VALIDATION_ERROR_CODES.FIELD_FORMAT_ERROR, 
            '音频文件格式不被 Dify AI 服务支持，请转换为 MP3 或 WAV 格式'
          );
        } else if (error.response?.status === 422) {
          ResponseUtils.sendError(res, VALIDATION_ERROR_CODES.FIELD_FORMAT_ERROR, '音频文件损坏或无法解析，请重新上传');
        } else if (error.response?.status === 429) {
          ResponseUtils.sendError(res, COMMON_ERROR_CODES.TOO_MANY_REQUESTS, '请求过于频繁，请稍后再试');
        } else if (error.response?.status === 500) {
          ResponseUtils.sendError(res, COMMON_ERROR_CODES.INTERNAL_SERVER_ERROR, 'Dify AI 服务内部错误，请稍后再试');
        } else if (error.response?.status === 503) {
          ResponseUtils.sendError(res, COMMON_ERROR_CODES.SERVICE_UNAVAILABLE, 'Dify AI 服务暂时不可用，请稍后再试');
        } else if (error.code === 'ECONNABORTED') {
          ResponseUtils.sendError(res, COMMON_ERROR_CODES.GATEWAY_TIMEOUT, '请求超时，请稍后再试');
        } else if (error.code === 'ENOTFOUND') {
          ResponseUtils.sendError(res, COMMON_ERROR_CODES.SERVICE_UNAVAILABLE, '无法连接到 Dify AI 服务，请检查网络连接');
        } else {
          ResponseUtils.sendError(res, COMMON_ERROR_CODES.SERVICE_UNAVAILABLE, '语音转文字服务暂时不可用，请稍后再试');
        }
      }
    } catch (error) {
      next(error);
    }
  }

  /**
   * 文字转语音
   * 使用 Dify API 的 /text-to-audio 接口
   */
  async textToVoice(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { text, message_id } = req.body;
      const userId = req.user?.id;

      if (!userId) {
        ResponseUtils.sendError(res, BUSINESS_ERROR_CODES.USER_NOT_FOUND, '用户不存在');
        return;
      }

      if (!text && !message_id) {
        ResponseUtils.sendError(res, VALIDATION_ERROR_CODES.REQUIRED_FIELD_MISSING, '文本内容或消息ID不能为空');
        return;
      }

      try {
        // 构建 FormData 用于 Dify API 调用
        const formData = new FormData();
        if (message_id) {
          formData.append('message_id', message_id);
        }
        if (text) {
          formData.append('text', text);
        }
        formData.append('user', userId.toString());

        // 调用 Dify 文字转语音 API
        const response = await axios.post(
          `${DIFY_CONFIG.baseUrl}/text-to-audio`,
          formData,
          {
            headers: {
              'Authorization': `Bearer ${DIFY_CONFIG.apiKey}`,
              ...formData.getHeaders()
            },
            responseType: 'arraybuffer'
          }
        );

        // 设置响应头
        res.setHeader('Content-Type', 'audio/wav');
        res.setHeader('Content-Disposition', 'attachment; filename="speech.wav"');

        // 返回音频数据
        res.send(response.data);

      } catch (error: any) {
        console.error('Dify 文字转语音 API 调用失败:', error);

        if (error.response?.status === 401) {
          ResponseUtils.sendError(res, COMMON_ERROR_CODES.UNAUTHORIZED, 'AI 服务认证失败');
        } else if (error.response?.status === 400) {
          ResponseUtils.sendError(res, VALIDATION_ERROR_CODES.FIELD_FORMAT_ERROR, '输入参数无效');
        } else {
          ResponseUtils.sendError(res, COMMON_ERROR_CODES.SERVICE_UNAVAILABLE, '文字转语音服务暂时不可用');
        }
      }
    } catch (error) {
      next(error);
    }
  }

  /**
   * 获取聊天历史
   */
  async getChatHistory(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const userId = req.user!.id;
      const { page = 1, pageSize = 20 } = req.query;
      const skip = (Number(page) - 1) * Number(pageSize);

      // 获取会话
      const conversation = await prisma.assistantConversation.findFirst({
        where: {
          userId: userId
        },
        include: {
          messages: {
            skip: skip,
            take: Number(pageSize),
            orderBy: {
              createdAt: 'desc'
            }
          }
        }
      });

      const messages = conversation?.messages || [];
      const total = await prisma.assistantMessage.count({
        where: {
          conversation: {
            userId: userId
          }
        }
      });

      ResponseUtils.success(res, {
        items: messages,
        pagination: {
          total,
          page: Number(page),
          pageSize: Number(pageSize),
          totalPages: Math.ceil(total / Number(pageSize))
        }
      }, '获取聊天历史成功');
    } catch (error) {
      next(error);
    }
  }

  /**
   * 获取 Dify 应用信息
   */
  async getAppInfo(_req: Request, res: Response, _next: NextFunction): Promise<void> {
    try {
      const response = await axios.get(
        `${DIFY_CONFIG.baseUrl}/info`,
        {
          headers: {
            'Authorization': `Bearer ${DIFY_CONFIG.apiKey}`
          }
        }
      );

      ResponseUtils.success(res, response.data, '获取应用信息成功');
    } catch (error: any) {
      console.error('获取 Dify 应用信息失败:', error);

      if (error.response?.status === 401) {
        ResponseUtils.sendError(res, COMMON_ERROR_CODES.UNAUTHORIZED, 'AI 服务认证失败');
      } else {
        ResponseUtils.sendError(res, COMMON_ERROR_CODES.SERVICE_UNAVAILABLE, '获取应用信息失败');
      }
    }
  }

  /**
   * 获取 Dify 应用参数
   */
  async getAppParameters(_req: Request, res: Response, _next: NextFunction): Promise<void> {
    try {
      const response = await axios.get(
        `${DIFY_CONFIG.baseUrl}/parameters`,
        {
          headers: {
            'Authorization': `Bearer ${DIFY_CONFIG.apiKey}`
          }
        }
      );

      ResponseUtils.success(res, response.data, '获取应用参数成功');
    } catch (error: any) {
      console.error('获取 Dify 应用参数失败:', error);

      if (error.response?.status === 401) {
        ResponseUtils.sendError(res, COMMON_ERROR_CODES.UNAUTHORIZED, 'AI 服务认证失败');
      } else {
        ResponseUtils.sendError(res, COMMON_ERROR_CODES.SERVICE_UNAVAILABLE, '获取应用参数失败');
      }
    }
  }

  /**
   * 获取快捷操作
   */
  async getQuickActions(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const userId = req.user?.id;
      if (!userId) {
        ResponseUtils.sendError(res, BUSINESS_ERROR_CODES.USER_NOT_FOUND, '用户不存在');
        return;
      }

      // 定义快捷操作列表
      const quickActions = [
        {
          id: '1',
          title: '音乐节信息',
          description: '获取音乐节基本信息和日程安排',
          icon: 'Calendar',
          action: 'info',
          color: '#667eea'
        },
        {
          id: '2',
          title: '场地导航',
          description: '查找场地位置和设施信息',
          icon: 'Location',
          action: 'navigation',
          color: '#45b7d1'
        },
        {
          id: '3',
          title: '艺人查询',
          description: '搜索艺人信息和演出安排',
          icon: 'User',
          action: 'artist',
          color: '#ff6b6b'
        },
        {
          id: '4',
          title: '演出推荐',
          description: '获取个性化演出推荐',
          icon: 'VideoPlay',
          action: 'recommendation',
          color: '#4ecdc4'
        },
        {
          id: '5',
          title: '语音对话',
          description: '使用语音与AI助手对话',
          icon: 'Microphone',
          action: 'voice_chat',
          color: '#f7b731'
        },
        {
          id: '6',
          title: '冷知识分享',
          description: '有趣的音乐节冷知识',
          icon: 'QuestionFilled',
          action: 'trivia',
          color: '#a55eea'
        }
      ];

      ResponseUtils.success(res, quickActions, '获取快捷操作成功');
    } catch (error) {
      next(error);
    }
  }

  /**
   * 停止响应
   * 使用 Dify API 的停止接口
   */
  async stopResponse(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { task_id } = req.body;

      if (!task_id) {
        ResponseUtils.sendError(res, VALIDATION_ERROR_CODES.REQUIRED_FIELD_MISSING, '任务ID不能为空');
        return;
      }

      try {
        // 调用 Dify 停止响应 API
        await axios.post(
          `${DIFY_CONFIG.baseUrl}/chat-messages/${task_id}/stop`,
          {},
          {
            headers: {
              'Authorization': `Bearer ${DIFY_CONFIG.apiKey}`,
              'Content-Type': 'application/json'
            }
          }
        );

        ResponseUtils.success(res, { task_id }, '停止响应成功');
      } catch (error: any) {
        console.error('停止 Dify 响应失败:', error);

        if (error.response?.status === 401) {
          ResponseUtils.sendError(res, COMMON_ERROR_CODES.UNAUTHORIZED, 'AI 服务认证失败');
        } else if (error.response?.status === 404) {
          ResponseUtils.sendError(res, BUSINESS_ERROR_CODES.RESOURCE_NOT_FOUND, '任务不存在或已完成');
        } else {
          ResponseUtils.sendError(res, COMMON_ERROR_CODES.SERVICE_UNAVAILABLE, '停止响应失败');
        }
      }
    } catch (error) {
      next(error);
    }
  }

  /**
   * 阿里云语音转文字
   * 使用阿里云 DashScope 语音识别服务
   */
  async aliyunVoiceToText(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const userId = req.user?.id;
      if (!userId) {
        ResponseUtils.sendError(res, BUSINESS_ERROR_CODES.USER_NOT_FOUND, '用户不存在');
        return;
      }

      if (!req.file) {
        ResponseUtils.sendError(res, VALIDATION_ERROR_CODES.REQUIRED_FIELD_MISSING, '请上传音频文件');
        return;
      }

      // 检查文件格式
      const allowedMimeTypes = [
        'audio/mpeg',           // MP3
        'audio/mp3',            // MP3 (某些系统)
        'audio/wav',            // WAV
        'audio/x-wav',          // WAV (某些系统)
        'audio/mp4',            // M4A
        'audio/x-m4a',          // M4A (某些系统)
        'audio/aac',            // AAC
        'audio/x-aac',          // AAC (某些系统)
        'audio/pcm',            // PCM
        'audio/x-pcm'           // PCM (某些系统)
      ];

      if (!allowedMimeTypes.includes(req.file.mimetype)) {
        // 删除临时文件
        try {
          fs.unlinkSync(req.file.path);
        } catch (unlinkError) {
          console.error('删除临时文件失败:', unlinkError);
        }

        ResponseUtils.sendError(res, VALIDATION_ERROR_CODES.FIELD_FORMAT_ERROR, '音频文件格式不支持');
        return;
      }

      // 检查文件大小 (DashScope 限制最大25MB)
      const maxFileSize = 25 * 1024 * 1024; // 25MB
      if (req.file.size > maxFileSize) {
        // 删除临时文件
        try {
          fs.unlinkSync(req.file.path);
        } catch (unlinkError) {
          console.error('删除临时文件失败:', unlinkError);
        }

        ResponseUtils.sendError(res, VALIDATION_ERROR_CODES.FIELD_FORMAT_ERROR, '音频文件过大，请上传小于25MB的文件');
        return;
      }

      try {
        // 检查阿里云配置
        if (!ALIYUN_CONFIG.apiKey) {
          throw new Error('阿里云 DashScope API Key 配置不完整');
        }

        console.log('开始阿里云 DashScope 语音转文字处理:', {
          fileName: req.file.originalname,
          fileSize: req.file.size,
          mimeType: req.file.mimetype,
          userId: userId
        });

        // 读取音频文件并转换为 base64
        const audioBuffer = fs.readFileSync(req.file.path);
        const audioBase64 = audioBuffer.toString('base64');

        // 构建 DashScope API 请求数据
        const requestBody = {
          model: "qwen-audio-asr",
          input: {
            messages: [
              {
                role: "user",
                content: [
                  {
                    audio: `data:${req.file.mimetype};base64,${audioBase64}`
                  }
                ]
              }
            ]
          },
          parameters: {
            incremental_output: false, // 不使用增量输出，一次性返回完整结果
            result_format: "text" // 返回纯文本格式
          }
        };

        console.log('发送 DashScope 语音识别请求:', {
          model: requestBody.model,
          fileSize: req.file.size,
          mimeType: req.file.mimetype
        });

        // 调用阿里云 DashScope API
        const response = await axios.post(
          ALIYUN_CONFIG.endpoint,
          requestBody,
          {
            headers: {
              'Authorization': `Bearer ${ALIYUN_CONFIG.apiKey}`,
              'Content-Type': 'application/json',
              'X-DashScope-SSE': 'disable' // 禁用 SSE，使用普通响应
            },
            timeout: 60000 // 60秒超时
          }
        );

        console.log('DashScope 语音识别响应状态:', response.status);
        console.log('识别结果:', response.data);

        // 删除临时文件
        try {
          fs.unlinkSync(req.file.path);
        } catch (unlinkError) {
          console.error('删除临时文件失败:', unlinkError);
        }

        // 处理响应结果
        const result = response.data;
        if (result.output && result.output.choices && result.output.choices.length > 0) {
          const choice = result.output.choices[0];
          const recognizedText = choice.message?.content?.[0]?.text || '';
          
          if (recognizedText) {
            ResponseUtils.success(res, {
              text: recognizedText,
              confidence: 0.95, // DashScope 不返回置信度，使用默认值
              duration: this.estimateAudioDuration(req.file.size, req.file.mimetype),
              fileInfo: {
                originalName: req.file.originalname,
                size: req.file.size,
                mimeType: req.file.mimetype
              },
              usage: result.usage || {},
              model: result.model || 'qwen-audio-asr'
            }, '阿里云 DashScope 语音转文字成功');
          } else {
            ResponseUtils.sendError(res, COMMON_ERROR_CODES.SERVICE_UNAVAILABLE, '语音识别结果为空');
          }
        } else {
          ResponseUtils.sendError(res, COMMON_ERROR_CODES.SERVICE_UNAVAILABLE, '语音识别失败，响应格式异常');
        }

      } catch (error: any) {
        console.error('阿里云 DashScope 语音转文字API调用失败:', error);

        // 删除临时文件
        try {
          fs.unlinkSync(req.file.path);
        } catch (unlinkError) {
          console.error('删除临时文件失败:', unlinkError);
        }

        // 根据不同的错误状态码返回相应的错误信息
        if (error.response?.status === 401) {
          ResponseUtils.sendError(res, COMMON_ERROR_CODES.UNAUTHORIZED, '阿里云 DashScope 服务认证失败，请检查 API Key');
        } else if (error.response?.status === 400) {
          ResponseUtils.sendError(res, VALIDATION_ERROR_CODES.FIELD_FORMAT_ERROR, '请求参数错误，请检查音频文件格式');
        } else if (error.response?.status === 413) {
          ResponseUtils.sendError(res, VALIDATION_ERROR_CODES.FIELD_FORMAT_ERROR, '音频文件过大，请上传小于25MB的文件');
        } else if (error.response?.status === 429) {
          ResponseUtils.sendError(res, COMMON_ERROR_CODES.TOO_MANY_REQUESTS, '请求过于频繁，请稍后再试');
        } else if (error.response?.status === 500) {
          ResponseUtils.sendError(res, COMMON_ERROR_CODES.INTERNAL_SERVER_ERROR, '阿里云 DashScope 服务内部错误，请稍后再试');
        } else if (error.code === 'ECONNABORTED') {
          ResponseUtils.sendError(res, COMMON_ERROR_CODES.GATEWAY_TIMEOUT, '请求超时，请稍后再试');
        } else if (error.code === 'ENOTFOUND') {
          ResponseUtils.sendError(res, COMMON_ERROR_CODES.SERVICE_UNAVAILABLE, '无法连接到阿里云 DashScope 服务，请检查网络连接');
        } else {
          ResponseUtils.sendError(res, COMMON_ERROR_CODES.SERVICE_UNAVAILABLE, '阿里云 DashScope 语音转文字服务暂时不可用，请稍后再试');
        }
      }
    } catch (error) {
      next(error);
    }
  }

  /**
   * 阿里云语音转文字 - 流式识别
   * 使用阿里云 DashScope 流式语音识别服务
   */
  async aliyunStreamVoiceToText(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const userId = req.user?.id;
      if (!userId) {
        ResponseUtils.sendError(res, BUSINESS_ERROR_CODES.USER_NOT_FOUND, '用户不存在');
        return;
      }

      // 检查阿里云配置
      if (!ALIYUN_CONFIG.apiKey) {
        ResponseUtils.sendError(res, COMMON_ERROR_CODES.SERVICE_UNAVAILABLE, '阿里云 DashScope API Key 配置不完整');
        return;
      }

      // 设置响应头，支持流式传输
      res.setHeader('Content-Type', 'text/event-stream');
      res.setHeader('Cache-Control', 'no-cache');
      res.setHeader('Connection', 'keep-alive');
      res.setHeader('Access-Control-Allow-Origin', '*');
      res.setHeader('Access-Control-Allow-Headers', 'Cache-Control');

      // 发送开始标记
      res.write('data: {"type": "start", "message": "开始语音识别..."}\n\n');
      res.flushHeaders();

      try {
        // 构建流式识别请求
        const requestBody = {
          model: "qwen-audio-asr",
          input: {
            messages: [
              {
                role: "user",
                content: [
                  {
                    audio: "https://dashscope.oss-cn-beijing.aliyuncs.com/audios/welcome.mp3" // 示例音频URL
                  }
                ]
              }
            ]
          },
          parameters: {
            incremental_output: true, // 启用增量输出
            result_format: "text"
          }
        };

        // 创建流式请求
        const streamResponse = await axios.post(
          ALIYUN_CONFIG.endpoint,
          requestBody,
          {
            headers: {
              'Authorization': `Bearer ${ALIYUN_CONFIG.apiKey}`,
              'Content-Type': 'application/json',
              'X-DashScope-SSE': 'enable' // 启用 SSE 流式响应
            },
            responseType: 'stream',
            timeout: 300000 // 5分钟超时
          }
        );

        const stream = streamResponse.data;
        let fullText = '';

        // 处理流式响应
        stream.on('data', (chunk: Buffer) => {
          try {
            const chunkStr = chunk.toString();
            const lines = chunkStr.split('\n');
            
            for (const line of lines) {
              if (line.startsWith('data: ')) {
                const data = line.slice(6);
                if (data === '[DONE]') {
                  // 流结束
                  res.write(`data: {"type": "end", "full_text": "${fullText}"}\n\n`);
                  res.flush();
                  res.end();
                  return;
                }
                
                try {
                  const parsed = JSON.parse(data);
                  console.log('DashScope 流式识别数据:', parsed);
                  
                  if (parsed.output && parsed.output.choices && parsed.output.choices.length > 0) {
                    const choice = parsed.output.choices[0];
                    const deltaText = choice.message?.content?.[0]?.text || '';
                    
                    if (deltaText) {
                      fullText += deltaText;
                      res.write(`data: {"type": "chunk", "text": "${deltaText}"}\n\n`);
                      res.flush();
                    }
                  }
                } catch (parseError) {
                  console.error('解析流式数据失败:', parseError);
                }
              }
            }
          } catch (parseError) {
            console.error('处理流式数据失败:', parseError);
          }
        });

        stream.on('end', () => {
          // 流结束
          res.write(`data: {"type": "end", "full_text": "${fullText}"}\n\n`);
          res.flush();
          res.end();
        });

        stream.on('error', (error: any) => {
          console.error('流式识别错误:', error);
          res.write(`data: {"type": "error", "message": "语音识别服务出现错误"}\n\n`);
          res.flush();
          res.end();
        });

      } catch (error: any) {
        console.error('阿里云 DashScope 流式语音识别失败:', error);
        res.write(`data: {"type": "error", "message": "启动语音识别服务失败"}\n\n`);
        res.flush();
        res.end();
      }

    } catch (error) {
      next(error);
    }
  }

  /**
   * 估算音频时长
   */
  private estimateAudioDuration(fileSize: number, mimeType: string): number {
    // 根据文件大小和格式估算时长
    let bytesPerSecond = 16000; // 默认16kbps
    
    if (mimeType.includes('mp3')) {
      bytesPerSecond = 128000 / 8; // 128kbps MP3
    } else if (mimeType.includes('wav')) {
      bytesPerSecond = 256000 / 8; // 256kbps WAV
    } else if (mimeType.includes('aac')) {
      bytesPerSecond = 192000 / 8; // 192kbps AAC
    }
    
    return Math.round(fileSize / bytesPerSecond);
  }
}
